<template>
  <view>
    <view class="datepicker_shade" :class="isShow ? 'datepicker_shade_active' : ''"></view>
    <view class="datepicker_wrap" :class="isShow ? 'datepicker_wrap_active' : ''" catchtouchmove="handleStop">
      <view class="datepicker_topinfo">
        {{ !hiddenConfirm ? '确认日期' : lunarTab ? returnDate.lunarStr : returnDate.solarStr }}
      </view>
      <view class="datepicker_select" :hidden="!hiddenConfirm">
        <view class="datepicker_class">
          <view :class="lunarTab?'':'active'" data-type="solar" @click="_solarLunarChange">公历</view>
          <view :class="lunarTab?'active':''" data-type="lunar" @click="_solarLunarChange">农历</view>
        </view>
        <picker-view indicator-style="height:40px" indicator-class="column_class" class="select_wrap"
                     :value="selectArr" @change="_pickerChange">
          <picker-view-column>
            <view v-for="(item,index) in yearArr" :key="index" style="line-height: 40px;">{{ item }}</view>
          </picker-view-column>
          <picker-view-column>
            <view v-for="(item,index) in monthArr" :key="index" style="line-height: 40px;">{{ item }}</view>
          </picker-view-column>
          <picker-view-column>
            <view v-for="(item,index) in dayArr" :key="index" style="line-height: 40px;">{{ item }}</view>
          </picker-view-column>
          <picker-view-column v-if="config.showHour">
            <view v-for="(item,index) in hourArr" :key="index" style="line-height: 40px;">{{ item }}</view>
          </picker-view-column>
        </picker-view>
      </view>
      <view class="datepicker_confirm" :hidden="hiddenConfirm">
        <view class="tip">请确认输入的时间是否正确</view>
        <view class="p">
          <text>{{ returnDate.solarStr }}</text>
        </view>
        <view class="p">
          <text>{{ returnDate.lunarStr }}</text>
        </view>
      </view>
      <view class="datepicker_bottom">
        <view @click="_cancel">{{ hiddenConfirm ? '取消' : '返回修改' }}</view>
        <view @click="confirm">{{ hiddenConfirm ? '完成' : '确认' }}</view>
      </view>
    </view>
  </view>
</template>

<script>
import solarLunar from './solarlunar';
// 设置年份数组1940-明年
const thisYear = new Date().getFullYear() + 1;
const dafaultYearArr = [];
for (let i = 1940; i <= thisYear; i++) {
  dafaultYearArr.push(i);
}
// 日期选择最大值最小值
const solarMinMonth = 2;
const solarMinDay = 8;
const maxLunar = solarLunar.solar2lunar(thisYear, 12, 31);
const lunarMaxMonth = maxLunar.lMonth;
const lunarMaxDay = maxLunar.lDay;

// 默认初始配置数据
const dafaultConfig = {
  confirm: true, //是否需要确认
  date: '1991-1-6', //默认日期(新历)
  hour: '-1', //默认时辰,未知
  showHour: true, //是否有时辰选项
  lunar: true, //默认展示农历
}

export default {
  name: "rui-datepicker",
  data() {
    return {
      // 默认初始配置数据
      config: {},
      returnDate: {
        lastTab: 'lunar', //最后确认tab,农历lunsr,公历solar
        year: '', //公历年
        month: '', //公历月
        day: '', //公历日
        lYear: '', //农历年
        lMonth: '', //农历月
        lDay: '', //农历日
        isLeap: '', //农历月是否为闰月
        lunarStr: '', //农历: 1991年十一月廿六 0子时
        solarStr: '', //公历: 1991年12月31日 0时
        thisStr: '', //当前在什么下返回
        hour: '', //时辰,为空表示不需要时辰，-1为未知时辰
      },
      // 选择块数据
      selectArr: [],
      yearArr: dafaultYearArr,
      monthArr: [],
      dayArr: [],
      hourArr: [],
      // 当前tab
      lunarTab: true,
      // 是否显示
      isShow: false,
      // 确认块隐藏
      hiddenConfirm: true,
    };
  },
  methods: {
    // 确认完成
    confirm() {
      // 判断是否需要确认
      if (this.config.confirm) {
        // 判断是否在确认步骤[完成&确认]
        if (this.hiddenConfirm === false) {
          this.isShow = false
          this.hiddenConfirm = true
          this.$emit('confirm', this.returnDate)
        } else {
          this.hiddenConfirm = false
        }
      } else {
        this.isShow = false
        this.hiddenConfirm = true
        this.$emit('confirm', this.returnDate)
      }
    },
    // 初始化插件数据并显示
    init(param) {
      // 合并对象,以默认配置为基础，返回新配置
      let defaultSet = Object.assign({}, dafaultConfig, param);
      // 检测数据合法性
      defaultSet = this._checkConfig(defaultSet);
      // 默认农历
      if (defaultSet.lunar == true) {
        //载入农历数据
        this._initlunar(defaultSet.date, defaultSet.hour);
      } else {
        //载入公历数据
        this._initsolar(defaultSet.date, defaultSet.hour);
      }
      // 设置配置，显示组件
      this.lunarTab = defaultSet.lunar === true ? true : false
      this.config = defaultSet
      this.isShow = true
      // 设置当前日期返回数据
      this._setReturnDate();
    },
    // 取消
    _cancel() {
      // 判断是否在确认步骤[返回修改&取消]
      if (this.hiddenConfirm === false) {
        this.hiddenConfirm = true
      } else {
        this.isShow = false
      }
    },
    // 检测配置的合法性，防止程序报错
    _checkConfig(conf) {
      // 是否需要确认:只能true 或 false
      if (typeof conf.confirm != 'boolean') {
        conf.confirm = dafaultConfig.confirm
      }
      // 是否有时辰选项:只能true 或 false
      if (typeof conf.showHour != 'boolean') {
        conf.showHour = dafaultConfig.showHour
      }
      // 默认展示农历:只能true 或 false
      if (typeof conf.lunar != 'boolean') {
        conf.lunar = dafaultConfig.lunar
      }
      // 时辰格式，区间[-1,24]
      if (parseInt(conf.hour) < -1 || parseInt(conf.hour) > 24 || conf.hour == '') {
        conf.hour = dafaultConfig.hour
      }
      // 日期格式，1991-12-31
      let confDate = new Date(conf.date);
      if (confDate == 'Invalid Date' || confDate.getFullYear() < 1940 || confDate.getFullYear() > 2030) {
        conf.date = dafaultConfig.date
      }
      return conf;
    },
    // 公农历切换
    _solarLunarChange(event) {
      const type = event.currentTarget.dataset.type;
      const thisDate = this.returnDate;

      // 农历下点击公历切换
      if (this.lunarTab !== true && type == 'lunar') {
        this.lunarTab = true
        this._initlunar(thisDate.year + '-' + thisDate.month + '-' + thisDate.day, thisDate.hour);
      }
      // 公历下点击农历切换
      if (this.lunarTab === true && type == 'solar') {
        this.lunarTab = false
        this._initsolar(thisDate.year + '-' + thisDate.month + '-' + thisDate.day, thisDate.hour);
      }
      this._setReturnDate();
    },
    // 切换picker
    _pickerChange(event) {
      let selectArr = event.detail.value;
      if (this.lunarTab === true) {
        //在农历下
        // 该年是否有闰月，0没有
        const leapMonth = solarLunar.leapMonth(selectArr[0] + 1940);
        const oldMonthArr = this.monthArr;
        // 刷新月份数组
        let monthArr = [];
        for (let i = 1; i <= 12; i++) {
          monthArr.push(this._getLunarName('month', i));
          // 判断是否有闰月
          if (leapMonth > 0 && i == leapMonth) {
            monthArr.push('闰' + this._getLunarName('month', i));
          }
        }

        // 日期数组
        let dayArr = [];
        let maxDay;
        //判断是否有闰月
        if (leapMonth > 0) {
          if (selectArr[1] < leapMonth) {
            //月份小于闰月，+1
            maxDay = solarLunar.monthDays(selectArr[0] + 1940, selectArr[1] + 1)
          } else {
            if (selectArr[1] == leapMonth) {
              maxDay = solarLunar.leapDays(selectArr[0] + 1940, leapMonth)
            } else {
              // 月份大于闰月
              maxDay = solarLunar.monthDays(selectArr[0] + 1940, selectArr[1])
            }
          }
        } else {
          //没有闰月，+1 (有闰月切换没闰月最大值处理)
          let thisMonth = (selectArr[1] + 1) > monthArr.length ? monthArr.length : (selectArr[1] + 1);
          maxDay = solarLunar.monthDays(selectArr[0] + 1940, thisMonth);
        }
        for (let i = 1; i <= maxDay; i++) {
          dayArr.push(this._getLunarName('day', i));
        }
        // 年切换月份位置修正：有闰年 -> 没闰年
        if (oldMonthArr.length > monthArr.length) {
          let oldLeapMonth = 0;
          for (let i = 0, max = oldMonthArr.length; i < max; i++) {
            if ('' + oldMonthArr[i].indexOf('闰') >= 0) {
              oldLeapMonth = i;
            }
          }
          selectArr[1] = ((selectArr[1] + 1) > oldLeapMonth) ? selectArr[1] - 1 : selectArr[1];
        }
        // 年份切换月份位置修正：没闰年 -> 有闰年
        if (oldMonthArr.length < monthArr.length) {
          selectArr[1] = ((selectArr[1] + 1) > leapMonth) ? selectArr[1] + 1 : selectArr[1];
        }
        // 判断是否超出月份最大值(有闰年切换没闰年的情况)
        selectArr[1] = selectArr[1] >= monthArr.length ? (monthArr.length - 1) : selectArr[1];
        // 判断是否超出日期最大值
        selectArr[2] = selectArr[2] >= maxDay ? maxDay - 1 : selectArr[2];
        // 判断到达年份最大
        if (selectArr[0] == thisYear - 1940) {
          // 有无闰月
          if (leapMonth > 0) {
            selectArr[1] = selectArr[1] > lunarMaxMonth ? lunarMaxMonth : selectArr[1];
            // 日期最大值
            if (selectArr[1] == lunarMaxMonth && (selectArr[2] + 1) > lunarMaxDay) {
              selectArr[2] = lunarMaxDay - 1;
            }
          } else {
            selectArr[1] = selectArr[1] > lunarMaxMonth - 1 ? lunarMaxMonth - 1 : selectArr[1];
            // 日期最大值
            if (selectArr[1] == (lunarMaxMonth - 1) && (selectArr[2] + 1) > lunarMaxDay) {
              selectArr[2] = lunarMaxDay - 1;
            }
          }
        }
        // 更新+最大值选择
        this.monthArr = monthArr
        this.dayArr = dayArr
        this.selectArr = selectArr
      } else {
        //在公历下
        // 刷新日期数组
        let dayArr = [];
        let maxDay = solarLunar.solarDays(selectArr[0] + 1940, selectArr[1] + 1);
        for (let i = 1; i <= maxDay; i++) {
          dayArr.push(i);
        }
        // 判断是否超出日期最大值
        selectArr[2] = selectArr[2] >= maxDay ? maxDay - 1 : selectArr[2];
        // 判断月份是否到达最小
        if (selectArr[0] == 0 && (selectArr[1] + 1) < solarMinMonth) {
          selectArr[1] = solarMinMonth - 1;
        }
        //判断年份月份到达最小
        if (selectArr[0] == 0 && (selectArr[1] + 1) == solarMinMonth && (selectArr[2] + 1) < solarMinDay) {
          selectArr[2] = solarMinDay - 1;
        }
        // 更新日期+最小值选择
        this.selectArr = selectArr
        this.dayArr = dayArr
      }
      // 设置当前日期返回数据
      this._setReturnDate();
    },
    // 设置返回数据，每次切换执行
    _setReturnDate() {
      // 微信picker-view的bug，重新设置位置
      this.selectArr = this.selectArr
      const selectArr = this.selectArr;
      let thisDateJson = {};
      thisDateJson.hour = this.config.showHour === false ? '' : selectArr[3] - 1;
      if (this.lunarTab === true) {
        //农历下
        thisDateJson.lastTab = 'lunar';
        // 公历数据
        thisDateJson.lYear = selectArr[0] + 1940;
        const leapMonth = solarLunar.leapMonth(selectArr[0] + 1940);
        if (leapMonth > 0) {
          thisDateJson.lMonth = selectArr[1] >= leapMonth ? selectArr[1] : selectArr[1] + 1;
        } else {
          thisDateJson.lMonth = selectArr[1] + 1;
        }
        thisDateJson.lDay = selectArr[2] + 1;
        thisDateJson.isLeap = (leapMonth > 0 && selectArr[1] == leapMonth) ? true : false;
        if (thisDateJson.isLeap == true) {
          thisDateJson.lunarStr = '农历:' + thisDateJson.lYear + '年闰' + this._getLunarName('month',
              thisDateJson.lMonth) + '' + this._getLunarName('day', thisDateJson.lDay);
        } else {
          thisDateJson.lunarStr = '农历:' + thisDateJson.lYear + '年' + this._getLunarName('month', thisDateJson
              .lMonth) + '' + this._getLunarName('day', thisDateJson.lDay);
        }
        // 农历数据
        let solarData = solarLunar.lunar2solar(thisDateJson.lYear, thisDateJson.lMonth, thisDateJson.lDay,
            thisDateJson.isLeap);
        thisDateJson.year = solarData.cYear;
        thisDateJson.month = solarData.cMonth;
        thisDateJson.day = solarData.cDay;
        thisDateJson.solarStr = '公历:' + thisDateJson.year + '年' + thisDateJson.month + '月' + thisDateJson.day +
            '日';
      } else {
        //公历下
        thisDateJson.lastTab = 'solar';
        // 公历数据
        thisDateJson.year = selectArr[0] + 1940;
        thisDateJson.month = selectArr[1] + 1;
        thisDateJson.day = selectArr[2] + 1;
        thisDateJson.solarStr = '公历:' + thisDateJson.year + '年' + thisDateJson.month + '月' + thisDateJson.day +
            '日';
        // 农历数据
        let lunarData = solarLunar.solar2lunar(thisDateJson.year, thisDateJson.month, thisDateJson.day);
        thisDateJson.lYear = lunarData.lYear;
        thisDateJson.lMonth = lunarData.lMonth;
        thisDateJson.lDay = lunarData.lDay;
        thisDateJson.isLeap = lunarData.isLeap;
        if (thisDateJson.isLeap == true) {
          thisDateJson.lunarStr = '农历:' + thisDateJson.lYear + '年闰' + this._getLunarName('month',
              thisDateJson.lMonth) + '' + this._getLunarName('day', thisDateJson.lDay);
        } else {
          thisDateJson.lunarStr = '农历:' + thisDateJson.lYear + '年' + this._getLunarName('month', thisDateJson
              .lMonth) + '' + this._getLunarName('day', thisDateJson.lDay);
        }
      }
      // 判断是否有选择时辰
      if (thisDateJson.hour !== '') {
        thisDateJson.solarStr += ' ' + (thisDateJson.hour < 0 ? '时辰未知' : (thisDateJson.hour + '时'));
        thisDateJson.lunarStr += ' ' + (thisDateJson.hour < 0 ? '时辰未知' : (this._getLunarName('hour',
            thisDateJson.hour) + '时'));
      }
      //判断当前模式返回thisStr
      if (this.lunarTab === true) {
        thisDateJson.thisStr = thisDateJson.lunarStr;
      } else {
        thisDateJson.thisStr = thisDateJson.solarStr;
      }
      this.returnDate = thisDateJson
    },
    // 返回中文农历名
    _getLunarName(type, number) {
      const monthArr = ['正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '腊月'];
      const dayArr = ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十', '十一', '十二', '十三', '十四', '十五',
        '十六', '十七', '十八', '十九', '二十', '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十', '三十一'
      ];
      const hourArr = ['0子', '1丑', '2丑', '3寅', '4寅', '5卯', '6卯', '7辰', '8辰', '9巳', '10巳', '11午', '12午', '13未',
        '14未', '15申', '16申', '17酉', '18酉', '19戌', '20戌', '21亥', '22亥', '23子'
      ];
      if (type === 'month') return monthArr[number - 1];
      if (type === 'day') return dayArr[number - 1];
      if (type === 'hour') return hourArr[number];
    },
    // 填充农历数据
    _initlunar(date, hour) {
      const dateArr = date.split("-");
      // 转换公历to农历
      const lunarData = solarLunar.solar2lunar(dateArr[0], dateArr[1], dateArr[2]);
      // 该年是否有闰月，0没有
      const leapMonth = solarLunar.leapMonth(lunarData.lYear);
      // 月份数组
      let monthArr = [];
      for (let i = 1; i <= 12; i++) {
        monthArr.push(this._getLunarName('month', i));
        // 判断是否有闰月
        if (leapMonth > 0 && i == leapMonth) {
          monthArr.push('闰' + this._getLunarName('month', i));
        }
      }
      // 日期数组
      let dayArr = [];
      let maxDay;
      // 该日期是否是闰月
      if (lunarData.isLeap) {
        maxDay = solarLunar.leapDays(dateArr[0], dateArr[1])
      } else {
        maxDay = solarLunar.monthDays(dateArr[0], dateArr[1])
      }
      for (let i = 1; i <= maxDay; i++) {
        dayArr.push(this._getLunarName('day', i));
      }

      // 时辰数组
      let hourArr = ['未知'];
      for (let i = 0; i <= 23; i++) {
        hourArr.push(this._getLunarName('hour', i) + '时');
      }
      // 设置位置
      let selectArr = [
        lunarData.lYear - 1940,
        (leapMonth > 0 && leapMonth <= lunarData.lMonth) ? lunarData.lMonth : lunarData.lMonth - 1,
        lunarData.lDay - 1,
        parseInt(hour) + 1
      ];
      this.lunarTab = true
      this.monthArr = monthArr
      this.dayArr = dayArr
      this.hourArr = hourArr
      this.selectArr = selectArr
    },
    // 填充公历数据
    _initsolar(date, hour) {
      const dateArr = date.split("-");
      // 月份数组
      let monthArr = [];
      for (let i = 1; i <= 12; i++) {
        monthArr.push(i);
      }

      // 日期数组
      let dayArr = [];
      let maxDay = solarLunar.solarDays(dateArr[0], dateArr[1])
      for (let i = 1; i <= maxDay; i++) {
        dayArr.push(i);
      }

      // 时辰数组
      let hourArr = ['未知'];
      for (let i = 0; i <= 23; i++) {
        hourArr.push(i + '时');
      }

      // 设置位置
      let selectArr = [dateArr[0] - 1940, dateArr[1] - 1, dateArr[2] - 1, parseInt(hour) + 1];
      this.lunarTab = false
      this.monthArr = monthArr
      this.dayArr = dayArr
      this.hourArr = hourArr
      this.selectArr = selectArr
    },
    // 阻塞事件冒泡，底层滑动
    handleStop() {
      return false;
    }
  }
}
</script>

<style scoped>
/*遮罩层*/
.datepicker_shade {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.2);
  z-index: 12;
  display: none;
}

/*日期选择框架*/
.datepicker_wrap {
  opacity: 0;
  position: fixed;
  width: 90%;
  max-width: 640px;
  left: 0;
  right: 0;
  top: 50%;
  margin-left: auto;
  margin-right: auto;
  background-color: #fff;
  box-shadow: 0 0 2px rgba(0, 0, 0, .4);
  border-radius: 10rpx;
  transform: translate3d(0, -300%, 0);
  transition: transform .5s ease-out;
  z-index: 31;
}

.datepicker_topinfo {
  color: #363837;
  font-size: 18px;
  text-align: center;
  padding: 20rpx 0;
  border-bottom: 1px solid #d4d4d4;
  font-weight: 700;
}

.datepicker_select {
  position: relative;
  text-align: center;
}

.datepicker_class {
  padding: 20rpx 0;
}

.datepicker_class view {
  display: inline-block;
  font-size: 14px;
  width: 30%;
  padding: 10rpx 0;
  text-align: center;
  color: #c91723;
  border: 1px solid #c91723;
}

.datepicker_class view:first-child {
  border-top-left-radius: 10rpx;
  border-bottom-left-radius: 10rpx
}

.datepicker_class view:last-child {
  border-top-right-radius: 10rpx;
  border-bottom-right-radius: 10rpx
}

.datepicker_class .active {
  background-color: #c91723;
  color: #fff
}

.datepicker_select .select_wrap {
  width: 100%;
  height: 120px;
  background-color: #f0f0f0;
}

.datepicker_select .column_class {
  border-top: 1px solid #d4d4d4;
  border-bottom: 1px solid #d4d4d4;
}

.datepicker_confirm {
  padding: 30rpx 20rpx;
  font-size: 16px;
  text-align: center;
}

.datepicker_confirm .tip {
  color: #666;
  margin-bottom: 20rpx;
}

.datepicker_confirm .p {
  line-height: 24px;
}

.datepicker_confirm .p text {
  color: #c91723
}

.datepicker_bottom {
  overflow: hidden;
  position: relative;
  border-top: 1px solid #d4d4d4;
  margin-top: 20rpx;
}

.datepicker_bottom view {
  color: #000;
  font-size: 16px;
  text-align: center;
  padding: 20rpx 0;
  float: left;
  width: 50%;
  box-sizing: border-box;
}

.datepicker_bottom view:last-child {
  background-color: #d00b0b;
  color: #fff;
  border-bottom-right-radius: 10rpx
}

/*活动状态*/
.datepicker_shade_active {
  display: block;
}

.datepicker_wrap_active {
  opacity: 1;
  transform: translate3d(0, -60%, 0);
}
</style>
